﻿/*****************************************************************//**
 * @file   VAOneXMLAdaptorFaces.h
 * @brief  VAOne读写Faces适配器
 *
 * @author lilongyuan (lilongyuan@diso.cn)
 * @date   2025-02-07
 *********************************************************************/
#ifndef VAONEXMLADAPTORFACES_H
#define VAONEXMLADAPTORFACES_H

#include "FITKAbstractVAOneXMLAdaptor.h"
#include "FITKAcousticsModel/FITKAbstractSEASubSysWithNodes.h"

namespace Acoustics
{
    class FITKAbstractSEAFace;
    class FITKAcousticsTriangles;
    class FITKSEADoublyCurvedFace;
    class FITKAcousticsFEFace;
}

namespace IO
{
    /**
     * @brief   VAOne读写Faces适配器
     * @author  lilongyuan (lilongyuan@diso.cn)
     * @date    2025-02-07
     */
    class FITKVAOneXMLIOAPI VAOneXMLAdaptorFaces : public FITKAbstractVAOneXMLAdaptor
    {
        FITKCLASS(IO, VAOneXMLAdaptorFaces);
    public:
        /**
         * @brief   构造函数
         * @author  lilongyuan (lilongyuan@diso.cn)
         * @date    2025-02-07
         */
        explicit VAOneXMLAdaptorFaces() = default;
        /**
         * @brief   析构函数
         * @author  lilongyuan (lilongyuan@diso.cn)
         * @date    2025-02-07
         */
        ~VAOneXMLAdaptorFaces() = default;
        /**
         * @brief   适配器读数据
         * @return  是否执行成功
         * @author  lilongyuan (lilongyuan@diso.cn)
         * @date    2025-02-07
         */
        virtual bool adaptR() override;
        /**
         * @brief   适配器写数据
         * @return  是否执行成功
         * @author  lilongyuan (lilongyuan@diso.cn)
         * @date    2025-02-07
         */
        virtual bool adaptW() override;
    private:
        /**
         * @brief     读取平板面数据
         * @param[i]  node FlatPlateFace节点
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-07
         */
        bool readFlatPlateFace(rapidxml::xml_node<char>* node);
        /**
         * @brief     读取单曲率板面数据
         * @param[i]  node SinglyCurvedFace节点
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-07
         */
        bool readSinglyCurvedFace(rapidxml::xml_node<char>* node);
        /**
         * @brief     读取双曲率板面数据
         * @param[i]  node DoublyCurvedShellFace节点
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-07
         */
        bool readDoublyCurvedShellFace(rapidxml::xml_node<char>* node);
        /**
         * @brief     读取FE面数据
         * @param[i]  node FEFace节点
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-27
         */
        bool readFEFace(rapidxml::xml_node<char>* node);
        /**
         * @brief     写入平板面数据
         * @param[i]  node Faces节点，data SEA面数据对象
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-08
         */
        bool writeFlatPlateFace(rapidxml::xml_node<char>* node, Acoustics::FITKAbstractSEAFace* data);
        /**
         * @brief     写入单曲率板面数据
         * @param[i]  node Faces节点，data SEA面数据对象
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-08
         */
        bool writeSinglyCurvedFace(rapidxml::xml_node<char>* node, Acoustics::FITKAbstractSEAFace* data);
        /**
         * @brief     写入双曲率板面数据
         * @param[i]  node Faces节点，data SEA面数据对象
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-08
         */
        bool writeDoublyCurvedShellFace(rapidxml::xml_node<char>* node, Acoustics::FITKAbstractSEAFace* data);
        /**
         * @brief     写入FE面数据
         * @param[i]  node Faces节点，data FE面数据对象
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-27
         */
        bool writeFEFace(rapidxml::xml_node<char>* node, Acoustics::FITKAcousticsFEFace* data);
    private:
        /**
         * @brief     读取拐点数据
         * @param[i]  node 节点
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-07
         */
        QList<int> readCorner(rapidxml::xml_node<char>* node);
        /**
         * @brief     获取节点列表数据
         * @param[i]  parentNode 父节点
         * @return    QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode>
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-07
         */
        QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> getNodeList(rapidxml::xml_node<char>* parentNode);
        /**
         * @brief     写出节点列表数据
         * @param[i]  parentNode 父节点，nodeList 节点列表
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-08
         */
        bool writeNodeRef(rapidxml::xml_node<char>* parentNode, QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> nodeList);
        /**
         * @brief     写出单曲率板面的拐点数据
         * @param[i]  node SinglyCurvedFace节点，nodeList 节点列表
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-10
         */
        bool writeCorner(rapidxml::xml_node<char>* node, QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> nodeList);
        /**
         * @brief     写出三角面片数据
         * @param[i]  parentNode 父节点，triangles 三角形单元列表
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-10
         */
        bool writeTriangle(rapidxml::xml_node<char>* parentNode, Acoustics::FITKAcousticsTriangles* triangles);
        /**
         * @brief     写出双曲率板面的环和顶点数据
         * @param[i]  node DoublyCurvedShellFace节点，data 双曲率板面数据
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-10
         */
        bool writeRingTip(rapidxml::xml_node<char>* node, Acoustics::FITKSEADoublyCurvedFace* data);
    private:
        /**
         * @brief     读取face_id数据模板
         * @param[i]  node 节点，data 数据对象
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-07
         */
        template <typename T>
        bool readFaceID(rapidxml::xml_node<char>* node, T data)
        {
            // node和data不能为空
            if (node == nullptr || data == nullptr) return false;

            // 初始化读取状态
            bool ok = true;

            // face_id
            int faceId = readIntAttribute(node, "face_id", &ok);
            if (!ok) return false;
            // 表层映射，仅限于读写调用
            data->setUserData(Core::FITKUserRole, faceId);
            // 添加到哈希表里
            ok &= setIdToHash(VAOne::FITKVAOneXMLHash::Node_Faces, faceId, data->getDataObjectID());

            return ok;
        }
        /**
         * @brief     读取声学包节点数据模板
         * @param[i]  parentNode 父节点，data 数据对象
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-07
         */
        template <typename T>
        bool readNoiseControlTreatments(rapidxml::xml_node<char>* parentNode, T data)
        {
            // parentNode和data不能为空
            if (parentNode == nullptr || data == nullptr) return false;

            // 初始化读取状态
            bool ok = true;

            // PositiveFace节点
            rapidxml::xml_node<char>* nodePositiveFace = parentNode->first_node("PositiveFace");
            if (nullptr == nodePositiveFace) return true;
            // trim_ref 外部声学包名称
            QString outsideTrimRef = readStrAttribute(nodePositiveFace, "trim_ref", &ok);
            if (!outsideTrimRef.isEmpty()) data->setOutsideNCTID(getIdOfHash(VAOne::FITKVAOneXMLHash::Node_NoiseControlTreatments, outsideTrimRef));
            // trim_coverage 外部声学包覆盖率
            double outsideTrimCoverage = readDoubleAttribute(nodePositiveFace, "trim_coverage", &ok);
            if (true == ok) data->setOutsideNCTCoveredArea(outsideTrimCoverage * 100);

            // NegativeFace节点
            rapidxml::xml_node<char>* nodeNegativeFace = parentNode->first_node("NegativeFace");
            if (nullptr == nodeNegativeFace) return true;
            // trim_ref 内部声学包名称
            QString insideTrimRef = readStrAttribute(nodeNegativeFace, "trim_ref", &ok);
            if (!insideTrimRef.isEmpty()) data->setInsideNCTID(getIdOfHash(VAOne::FITKVAOneXMLHash::Node_NoiseControlTreatments, insideTrimRef));
            // trim_coverage 内部声学包覆盖率
            double insideTrimCoverage = readDoubleAttribute(nodeNegativeFace, "trim_coverage", &ok);
            if (ok) data->setInsideNCTCoveredArea(insideTrimCoverage * 100);

            return ok;
        }
        /**
         * @brief     读取三角面片数据模板
         * @param[i]  parentNode 父节点，data 数据对象
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-08
         */
        template <typename T>
        bool readTriangleFace(rapidxml::xml_node<char>* parentNode, T data)
        {
            // parentNode和data不能为空
            if (parentNode == nullptr || data == nullptr) return false;

            // 初始化读取状态
            bool ok = true;

            // 获取三角形列表
            Acoustics::FITKAcousticsTriangles* triangles = data->getTriangleMesh();
            if (nullptr == triangles) return false;

            // 设置是否读取到三角形面片状态，默认false
            if (triangles->getElementCount() != 0) data->setFEFace(true);

            // 遍历Triangle节点数据
            for (rapidxml::xml_node<char>* child = parentNode->first_node("Triangle"); child != nullptr; child = child->next_sibling())
            {
                // 下一个节点不是Triangle时，跳出当前循环
                QString name = child->name();
                if (name != "Triangle") continue;
                
                // 重置三角面片读取状态
                data->setFEFace(true);

                //读取三角单元信息
                // node_id1 第一个拐点
                int value1 = readIntAttribute(child, "node_id1", &ok);
                if (true != ok) continue;
                value1 = getIdOfHash(VAOne::FITKVAOneXMLHash::Node_Nodes, value1);
                // node_id2 第二个拐点
                int value2 = readIntAttribute(child, "node_id2", &ok);
                if (!ok) continue;
                value2 = getIdOfHash(VAOne::FITKVAOneXMLHash::Node_Nodes, value2);
                // node_id3 第三个拐点
                int value3 = readIntAttribute(child, "node_id3", &ok);
                if (true != ok) continue;
                value3 = getIdOfHash(VAOne::FITKVAOneXMLHash::Node_Nodes, value3);

                // 创建三角形单元对象
                Interface::FITKAbstractElement* element = Interface::FITKElementFactory::createElement(Interface::FITKModelEnum::FITKEleType::Tri3);
                // 设置单元节点ID
                element->setNodeID(QList<int>() << value1 << value2 << value3);
                // 追加单元
                triangles->appendElement(element);
            }

            return ok;
        }
        /**
         * @brief     写出声学包节点数据模板
         * @param[i]  parentNode 父节点，data 数据对象
         * @return    是否执行成功
         * @author    lilongyuan (lilongyuan@diso.cn)
         * @date      2025-02-08
         */
        template <typename T>
        bool writeNoiseControlTreatments(rapidxml::xml_node<char>* parentNode, T data)
        {
            // parentNode和data不能为空
            if (parentNode == nullptr || data == nullptr) return false;

            // 初始化读取状态
            bool ok = true;

            // PositiveFace节点
            rapidxml::xml_node<char>* nodePositiveFace = createChildNode(parentNode, "PositiveFace", rapidxml::node_element);
            if (nodePositiveFace == nullptr) return false;
            // trim_ref 外部声学包名称
            QString trimRef = getNCTName(data->getOutsideNCTID());
            if (!trimRef.isEmpty()) ok &= writeAttribute(nodePositiveFace, "trim_ref", trimRef);
            // trim_coverage 外部声学包覆盖率
            ok &= writeAttribute(nodePositiveFace, "trim_coverage", data->getOutsideNCTCoveredArea() / 100);

            // NegativeFace节点
            rapidxml::xml_node<char>* nodeNegativeFace = createChildNode(parentNode, "NegativeFace", rapidxml::node_element);
            if (nodeNegativeFace == nullptr) return false;
            // trim_ref 内部声学包名称
            trimRef = getNCTName(data->getInsideNCTID());
            if (!trimRef.isEmpty()) ok &= writeAttribute(nodeNegativeFace, "trim_ref", trimRef);
            // trim_coverage 内部声学包覆盖率
            ok &= writeAttribute(nodeNegativeFace, "trim_coverage", data->getInsideNCTCoveredArea() / 100);

            return ok;
        }
    };
    Register2FITKIOAdaptorFactory(VAOneXML, Faces, VAOneXMLAdaptorFaces)
}

#endif // VAONEXMLADAPTORFACES_H


